﻿namespace NHCodeFirst.FluentMapper
{
    using System;
    using System.Linq.Expressions;
    using Enums;
    using HbmModel;
    using Helpers;
    using Version = HbmModel.Version;

    public class ClassMapper<TEntity> : ClassMapperBase<ClassMapper<TEntity>>
    {
        private readonly Class @class;

        internal ClassMapper(Class @class) : base(@class)
        {
            this.@class = @class;
            this.@class.ElementType = "class";
            child = this;
        }

        public DiscriminatorMapper Discriminator
        {
            get
            {
                if (@class.Discriminator == null)
                {
                    @class.Discriminator = new Discriminator();
                    @class.Discriminator.Column = new Column();
                }
                return new DiscriminatorMapper(@class.Discriminator);
            }
        }

        public ClassMapper<TEntity> SchemaAction(SchemaAction value)
        {
            @class.SchemaAction = value.ToString().ToLower();
            return this;
        }

        public ClassMapper<TEntity> Mutable(bool value)
        {
            @class.Mutable = value.ToString().ToLower();
            return this;
        }

        public ClassMapper<TEntity> OptimisticLock(OptimisticLock value)
        {
            @class.OptimisticLock = value.ToString().ToLower();
            return child;
        }

        public ClassMapper<TEntity> Where(bool value)
        {
            @class.Where = value.ToString().ToLower();
            return child;
        }

        public ClassMapper<TEntity> SubSelect(bool value)
        {
            @class.SubSelect = value.ToString().ToLower();
            return child;
        }

        public ClassMapper<TEntity> RowId(string value)
        {
            @class.RowId = value;
            return child;
        }

        public ClassMapper<TEntity> Check(string value)
        {
            @class.Check = value;
            return child;
        }

        public ClassMapper<TEntity> Catalog(string value)
        {
            @class.Catalog = value;
            return child;
        }

        public ClassMapper<TEntity> Polymorphism(ClassPolymorphism value)
        {
            @class.Polymorphism = value.ToString().ToLower();
            return child;
        }

        public IdMapper Id<TProperty>(Expression<Func<TEntity,TProperty>> selector)
        {
            var propertyName = new ExpressionHelper().GetPropertyName(selector);
            if (!@class.Usages.ContainsKey(propertyName))
                @class.Usages.Add(propertyName, PropertyUsage.ID);
            else
                @class.Usages[propertyName] = PropertyUsage.ID;
            if (@class.Id == null)
            {
                @class.Id = new Id
                                {
                                    Generator = new Generator(),
                                    Column = new Column(),
                                    Type = new TypeE(),
                                    Name = propertyName
                                };
            }
            return new IdMapper(@class.Id);            
        }

        public ClassMapper<TEntity> Table(string table, string schema = "dbo")
        {
            @class.Table = table;
            @class.Schema = schema;
            return this;
        }

        public VersionMapper Version<TProperty>(Expression<Func<TEntity, TProperty>> selector)
        {
            @class.TimeStamp = null;
            var propertyName = new ExpressionHelper().GetPropertyName(selector);
            if (!@class.Usages.ContainsKey(propertyName))
                @class.Usages.Add(propertyName, PropertyUsage.Version);
            else
                @class.Usages[propertyName] = PropertyUsage.Version;
            @class.Version = new Version
                                 {
                                     Column = new Column(),
                                     Type = new TypeE(),
                                     Name = propertyName
                                 };
            return new VersionMapper(@class.Version);
        }

        public TimeStampMapper TimeStamp<TProperty>(Expression<Func<TEntity,TProperty>> selector)
        {
            @class.Version = null;
            var propertyName = new ExpressionHelper().GetPropertyName(selector);
            if (!@class.Usages.ContainsKey(propertyName))
                @class.Usages.Add(propertyName, PropertyUsage.TimeStamp);
            else
                @class.Usages[propertyName] = PropertyUsage.TimeStamp;
            @class.TimeStamp = new TimeStamp
                                   {
                                       Name = propertyName
                                   };
            return new TimeStampMapper(@class.TimeStamp);
        }
    }
}